package com.ssj.utils;

import com.ssj.annotation.*;

import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class MybatisUtils {
    public static <T> T getMapper(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("该 " + method.getName() + " 方法被调用了");
                if (method.isAnnotationPresent(Insert.class)) {
                    Insert annotation = method.getAnnotation(Insert.class);
                    String sql = annotation.value();
                    return executeInsert(method,sql, args);
                } else if (method.isAnnotationPresent(Delete.class)) {
                    Delete annotation = method.getAnnotation(Delete.class);
                    String sql = annotation.value();
                    return executeDelete(method,sql, args);
                } else if (method.isAnnotationPresent(Update.class)) {
                    Update annotation = method.getAnnotation(Update.class);
                    String sql = annotation.value();
                    return executeUpdate(method,sql, args);
                } else if (method.isAnnotationPresent(Select.class)) {
                    Select annotation = method.getAnnotation(Select.class);
                    String sql = annotation.value();
                    return executeQuery(sql, args, method);
                }
                return null;
            }

            private int executeInsert(Method method,String sql, Object[] args) throws Exception {
                if (args.length == 0) {
                    System.out.println("args长度为0");
                    throw new IllegalArgumentException("Invalid argument for insert operation");
                }
                //插入参数
                String[] insertParam = SQLUtils.getInsertParams(sql);
                //参数绑定
                ConcurrentHashMap<String, Object> paramMap = getMethodParam(method, args);
                //将参数值加入list
                List<Object> paramValueList = addParamToList(insertParam, paramMap);
                //预编译sql语句
                sql = SQLUtils.replaceParam(sql, insertParam);

                try (Connection connection = JdbcUtils.getConnection();
                     PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                    JdbcUtils.start();
//                    setPreparedStatementParameters(preparedStatement, args[0]);
                    if (paramValueList!=null){
                        // 设置PreparedStatement参数
                        for (int i = 0; i < paramValueList.toArray().length; i++) {
                            // 将方法参数设置到PreparedStatement中
                            preparedStatement.setObject(i + 1, paramValueList.get(i));
                        }
                    }

                    int rows = preparedStatement.executeUpdate();
                    JdbcUtils.commit();
                    return rows;
                }catch (Exception e){
                    JdbcUtils.rollback();
                    JdbcUtils.commit();
                    e.printStackTrace();
                    throw new RuntimeException("数据库连接异常");
                }finally {
                    JdbcUtils.close();
                }
            }
            private int executeUpdate(Method method,String sql, Object[] args) throws Exception {
                //插入参数
                List<Object> insertParam = SQLUtils.getUpdateParams(sql);
                //参数绑定
                ConcurrentHashMap<String, Object> paramMap = getMethodParam(method, args);
                //将参数值加入list
                List<Object> paramValueList = addParamToList(insertParam, paramMap);
                //预编译sql语句
                sql = SQLUtils.replaceParam(sql, insertParam);
                try (Connection connection = JdbcUtils.getConnection();
                     PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                    JdbcUtils.start();
                    for (int i = 0; i < paramValueList.toArray().length; i++) {
                        System.out.println("修改参数: " + args[i]);
                        preparedStatement.setObject(i + 1, paramValueList.get(i));
                    }

                    int rows = preparedStatement.executeUpdate();
                    JdbcUtils.commit();
                    return rows;
                } catch (Exception e) {
                    JdbcUtils.rollback();
                    throw e;
                } finally {
                    JdbcUtils.close();
                }
            }
            private int executeDelete(Method method,String sql, Object[] args) throws Exception {
                //插入参数
                List<Object> insertParam = SQLUtils.getSelectParams(sql);
                //参数绑定
                ConcurrentHashMap<String, Object> paramMap = getMethodParam(method, args);
                //将参数值加入list
                List<Object> paramValueList = addParamToList(insertParam, paramMap);
                //预编译sql语句
                sql = SQLUtils.replaceParam(sql, insertParam);
                try (Connection connection = JdbcUtils.getConnection();
                     PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                    JdbcUtils.start();
                    for (int i = 0; i < paramValueList.toArray().length; i++) {
                        System.out.println("删除参数: " + args[i]);
                        preparedStatement.setObject(i + 1, paramValueList.get(i));
                    }

                    int rows = preparedStatement.executeUpdate();
                    JdbcUtils.commit();
                    return rows;
                } catch (Exception e) {
                    JdbcUtils.rollback();
                    throw e;
                } finally {
                    JdbcUtils.close();
                }
            }

            // 执行查询操作
            private Object executeQuery(String sql, Object[] args, Method method) throws Exception {
                //插入参数
                List<Object> selectParams = SQLUtils.getSelectParams(sql);
                //参数绑定
                ConcurrentHashMap<String, Object> paramMap = getMethodParam(method, args);
                //将参数值加入list
                List<Object> paramValueList = addParamToList(selectParams, paramMap);
                //预编译sql语句
                sql = SQLUtils.replaceParam(sql, selectParams);
                try (Connection connection = JdbcUtils.getConnection();
                     PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                    System.out.println("args.length="+args);
                    if (args!=null){
                        // 设置PreparedStatement参数
                        for (int i = 0; i < paramValueList.toArray().length; i++) {
                            // 将方法参数设置到PreparedStatement中
                            preparedStatement.setObject(i + 1, paramValueList.get(i));
                        }
                    }
                    // 执行查询操作
                    ResultSet resultSet = preparedStatement.executeQuery();

                    // 获取方法的返回类型
                    Class<?> returnType = method.getReturnType();
                    // 如果返回类型是List，则将结果集映射为List对象
                    if (returnType == List.class) {
                        return mapResultSetToList(resultSet, getGenericReturnType(method));
                    } else {
                        // 如果不是List，则将结果集映射为单个对象
                        if (resultSet.next()) {
                            return mapResultSetToObject(resultSet, returnType);
                        }
                    }
                    return null;
                }catch (Exception e){
                    e.printStackTrace();
                    throw new RuntimeException("数据库连接异常");
                }finally {
                    JdbcUtils.close();
                }
            }

            private void setPreparedStatementParameters(PreparedStatement preparedStatement, Object param) throws Exception {
                System.out.println(param);
                Class<?> clazz = param.getClass();
                Field[] fields = clazz.getDeclaredFields();
                int index = 1;

                for (Field field : fields) {
                    field.setAccessible(true);
                    Object value = field.get(param);
                    System.out.println("insert--- 参数："+value);
//                    if (value==null) continue;
                    preparedStatement.setObject(index++, value);
                }
            }



            // 将ResultSet映射为对象列表
            private <T> List<T> mapResultSetToList(ResultSet resultSet, Class<T> clazz) throws Exception {
                List<T> list = new ArrayList<>();
                // 遍历结果集，将每行数据映射为对象并添加到列表中
                while (resultSet.next()) {
                    list.add(mapResultSetToObject(resultSet, clazz));
                }
                return list;
            }

            // 将ResultSet映射为单个对象
            private <T> T mapResultSetToObject(ResultSet resultSet, Class<T> clazz) throws Exception {
                T obj = clazz.getDeclaredConstructor().newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();
                // 遍历结果集的元数据，将每列的数据映射到对象的相应字段中
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    String columnName = metaData.getColumnName(i);
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(obj, resultSet.getObject(i));
                }
                return obj;
            }

            // 获取方法的泛型返回类型
            private Class<?> getGenericReturnType(Method method) {
                Type returnType = method.getGenericReturnType();
                // 如果返回类型是参数化类型，则获取实际的类型参数
                if (returnType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) returnType;
                    return (Class<?>) parameterizedType.getActualTypeArguments()[0];
                }
                return Object.class;
            }
            // 判断一个类是否为基本类型或包装类型
            private  boolean isPrimitiveOrWrapper(Class<?> type) {
                return type.isPrimitive() || type == Boolean.class || type == Byte.class ||
                        type == Character.class || type == Double.class || type == Float.class ||
                        type == Integer.class || type == Long.class || type == Short.class ||
                        type == String.class;
            }

            private ConcurrentHashMap<String, Object> getMethodParam(Method method, Object[] args) {
                ConcurrentHashMap<String, Object> paramMap = new ConcurrentHashMap<>();
                Parameter[] parameters = method.getParameters();
                for (int i = 0; i < parameters.length; i++) {
                    Param param = parameters[i].getAnnotation(Param.class);
                    if (param == null) {
                        continue;
                    }
                    String paramName = param.value();
                    System.out.println("paramName="+paramName);
                    Object paramValue = args[i];
                    System.out.println("paramValue="+paramValue);

                    // 如果参数不是基本类型或包装类型，则将其属性名和值添加到 paramMap 中
                    if (!isPrimitiveOrWrapper(paramValue.getClass())) {
                        addObjectFieldsToParamMap(paramMap, paramName, paramValue);
                    } else {
                        paramMap.put(paramName, paramValue);
                    }
                }
                return paramMap;
            }

            // 将对象的属性名和值添加到 paramMap 中
            private void addObjectFieldsToParamMap(ConcurrentHashMap<String, Object> paramMap, String paramName, Object paramValue) {
                Field[] fields = paramValue.getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    try {
                        Object fieldValue = field.get(paramValue);
                        System.out.println("filedValue="+fieldValue);
                        String fieldName = paramName + "." + field.getName();
                        System.out.println("fieldName="+fieldName.substring(fieldName.indexOf(".")+1));
                        paramMap.put(fieldName.substring(fieldName.indexOf(".")+1), fieldValue);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            private List<Object> addParamToList(String[] insertParam, ConcurrentHashMap<String, Object> paramMap) {
                List<Object> paramValueList = new ArrayList<>();
                for (String param : insertParam) {
                    Object paramValue = paramMap.get(param.trim());
                    paramValueList.add(paramValue);
                }
                return paramValueList;
            }
            private List<Object> addParamToList(List<Object> insertParam, ConcurrentHashMap<String, Object> paramMap) {
                List<Object> paramValueList = new ArrayList<>();
                for (Object param : insertParam) {
                    Object paramValue = paramMap.get(param);
                    paramValueList.add(paramValue);
                }
                return paramValueList;
            }

        });
    }
}